<?php

namespace app\api\controller;


use app\api\model\FareOrder;
use app\api\services\OrderFunc;
use app\api\services\OrderService;
use app\api\services\Refund;
use ba\PayLib;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Log;
use Throwable;
use think\facade\Db;
use app\common\controller\Frontend;
use app\api\model\Order as OrderModel;
use app\admin\model\Technician;
use Yansongda\Pay\Pay;

class Order extends Frontend
{
    protected array $noNeedLogin = ['TaskCancelOrder', 'refund', 'TaskCompleteOrder'];
    protected array $noNeedPermission = ['*'];
    protected OrderModel $model;

    public function initialize(): void
    {
        $this->model = new OrderModel;
        parent::initialize();
    }

    /**
     * 创建订单
     */
    public function create(): void
    {
        $params = $this->request->post();
        $service = Db::table("ba_service")->where([
            'service_id' => $params['service_id'] ?? 0,
        ])->find();
        if (!$service) {
            $this->error("服务项目不存在");
        }
        if (!validatePhoneNumber($params['address_tel'] ?? '')) {
            $this->error("请输入正确的手机号");
        }
        $technician = Db::table("ba_technician")
            ->where(['technician_id' => $params['technician_id']])
            ->find();
        if (!$technician) {
            $this->error("技师不存在");
        }

        //        #计算距离
        $km = distance($technician['lat'], $technician['lng'], $params['address_lat'], $params['address_lng']);
        Log::info("technician_id-" . $params['technician_id']);
        Log::info("lat-{$technician['lat']} lng-{$technician['lng']}");
        Log::info("lat-{$params['address_lat']} lng- {$params['address_lng']} ");
        Log::info("km- " . $km);
        Log::info("farthest_order_distance- " . get_sys_config('farthest_order_distance'));
        if ($km > get_sys_config('farthest_order_distance')) {
            $this->error("超出平台规定服务范围");
        }

        #订单结束时间
        $serviceEndTime = strtotime($params['service_start_time']) + ($service['service_duration'] * $params['service_num'] * 60);

        $isTimeConflict = Db::name('order_reservation')->where('technician_id', $params['technician_id'])->where('reservation_time', '=', date('Y-m-d H:i:s', strtotime($params['service_start_time'])))->find();
        Log::info("order-" . json_encode($isTimeConflict));
        if ($isTimeConflict) {
            $this->error('时间已被预约');
        }


        $order_sn = $this->model->orderSn();
        // 发起支付的费用
        $service_total_price = bcmul($service['service_price'], $params['service_num'], 2);
        if (!empty($params['user_coupon_id'])) {
            // 如果选择了优惠券
            Log::info('user_coupon_id ' . $params['user_coupon_id']);
            $usercoupon = Db::table("ba_user_coupon")
                ->where([
                    'user_coupon_id' => $params['user_coupon_id'],
                    'is_apply' => 1,
                ])
                ->find();

            if (empty($usercoupon)) {
                $this->error("优惠券不存在");
            }
            if ($usercoupon['is_apply'] == 2) {
                $this->error('优惠券已被使用');
            }
            if (!empty($usercoupon['end_time'])) {
                if (strtotime($usercoupon['end_time']) < time()) {
                    $this->error('优惠券已过期');
                }
            }

            Db::table("ba_user_coupon")
                ->where([
                    'user_coupon_id' => $params['user_coupon_id'],
                    'is_apply' => 1,
                ])->update([
                        'is_apply' => 2,
                    ]);

            // 支付费用减去优惠券优惠的价格
            $coupon = Db::table("ba_coupon")
                ->where([
                    'coupon_id' => $usercoupon['coupon_id']
                ])
                ->find();
            $service_total_price = bcsub($service_total_price, $coupon['price'], 2);
        }

        $fare_price = "0";
        #减去车费
        if ($technician['is_travel'] == 0) {
            $km = distance($technician['lat'], $technician['lng'], $params['address_lat'], $params['address_lng']);
            $fare_price = fare_total($this->request->param('area_id'), $km);
        }
        $service_total_price = bcadd($service_total_price, $fare_price, 2);

        $save = [];
        $save['user_coupon_id'] = $params['user_coupon_id'] ?? '';
        $save['service_id'] = $params['service_id'];
        $save['user_id'] = $this->auth->id;
        $save['service_start_time'] = $params['service_start_time'];
        $save['service_price'] = $service['service_price'];
        $save['service_duration'] = $service['service_duration'];
        $save['service_num'] = $params['service_num'] ?? 1;
        $save['service_total_price'] = $service_total_price;
        $save['order_sn'] = $order_sn;
        $save['create_time'] = date("Y-m-d H:i:s", time());
        $save['order_state'] = 'ToBePaid';
        $save['technician_id'] = $params['technician_id'];
        $save['address_username'] = $params['address_username'];
        $save['address_tel'] = $params['address_tel'];
        $save['address_house'] = $params['address_house'];
        $save['address_content'] = $params['address_content'];
        $save['address_lng'] = $params['address_lng'];
        $save['address_lat'] = $params['address_lat'];
        $save['technician_tel'] = $technician['tel'];
        $save['remarks'] = $params['remarks'];
        $save['area_id'] = $params['area_id'];
        $save['type'] = 1;
        $save['fare_price'] = $fare_price; //车费
        // halt($save);

        $create = $this->model->create($save);
        #记录订单状态
        setOrderStateLog($create->id, 'ToBePaid');


        if (!$create) {
            $this->error('订单创建失败');
        }


        if (isset($params['pay_type']) && $params['pay_type'] == 1) {
            $this->success("订单创建成功", ['order_sn' => $order_sn]);
        }

        #微信支付 JSApi支付
        $order = [
            'out_trade_no' => $order_sn,
            'description' => $service['service_name'],
            'amount' => [
                'total' => $service_total_price * 100, //分
            ],
            'payer' => [
                'openid' => $this->openid(),
            ],
            'attach' => 'orderPayCallback'   #扩展信息
        ];
        $result = Pay::wechat(PayLib::getConfig())->mp($order);
        Log::info('创建订单 支付返回信息' . json_encode($result));
        $this->success("订单创建成功", ['order_sn' => $order_sn, 'pay_url' => $result]);
    }


    /**
     * 订单列表
     * @param string $order_state 订单状态
     * @param string $search 搜索
     * @return void
     * @throws \think\db\exception\DbException
     */
    public function list()
    {
        $search = $this->request->get('search');
        $order_state = $this->request->get('order_state');
        $where = [];
        if (!empty($search)) {
            $where[] = ['o.order_sn|s.service_name|t.technician_name', 'like', "%{$search}%"];
        }
        if (!empty($order_state)) {
            $where[] = ['order_state', 'in', $order_state];
        }

        $ret = Db::name('order')
            ->alias('o')
            ->join('ba_service s', 'o.service_id = s.service_id')
            ->join('ba_technician t', 'o.technician_id = t.technician_id')
            //            ->join('ba_fare_order f', 'o.id = f.order_id', "LEFT")
            ->where('o.user_id', $this->auth->id)
            ->where($where)
            ->field('o.*, s.service_name, s.service_title, s.service_price,s.service_duration, s.service_cover_img, t.technician_name, t.avatar, t.score, t.service_order_num')//,f.*
            ->hidden(['o.technician_tel'])
            ->order('create_time', 'desc')
            ->paginate(20)->each(function ($item) {
                $item['avatar'] = IMAGE_URL . $item['avatar'];
                $item['service_cover_img'] = IMAGE_URL . $item['service_cover_img'];
                $item['service_start_time'] = date("Y-m-d H:i", strtotime($item['service_start_time']));
                //                if (!empty($item['fare_price_imgs'])) $item['fare_price_imgs'] = IMAGE_URL . $item['fare_price_imgs'];
    
                #如果是待支付状态，计算剩余支付时间
                if ($item['order_state'] == 'ToBePaid') {
                    $remaining_time = get_sys_config('remaining_time') * 60;
                    $item['remaining_time'] = strtotime($item['create_time']) + $remaining_time;
                }

                #如果订单在服务中，但是加钟时间和技师服务时间有冲突则不显示加钟按钮
                $item['is_show_add_clock_btn'] = false;
                if ($item['order_state'] == 'Start' && $this->isTimeConflict($item, 1)) {
                    $item['is_show_add_clock_btn'] = true;
                }

                //                if (!empty($item['fare_fare_price_imgs'])) {
//                    $item['fare_fare_price_imgs'] = explode(',', $item['fare_fare_price_imgs']);
//                    foreach ($item['fare_fare_price_imgs'] as &$img) {
//                        $img = IMAGE_URL . $img;
//                    }
//                    unset($img);
//                }
                $item['price'] = bcsub($item['service_total_price'], (string) $item['fare_price'], 2);

                return $item;
            });


        $this->success("获取成功", [
            'list' => $ret->items(),
            'total' => $ret->total(),
        ]);
    }


    /**
     * TODO 待完善支付后取消 和技师上门中取消
     *  取消订单
     * @param int $order_id 订单ID
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function cancelOrder(): void
    {
        Log::info('取消订单' . json_encode($this->request->param()));
        $order_id = (int) $this->request->param('order_id');
        if (empty($order_id)) {
            $this->error("order_id 为必填项");
        }

        $cancel_remarks = $this->request->param('cancel_remarks') ?? '';


        $orderInfo = $this->model->where('id', $order_id)->where('user_id', $this->auth->id)->find();

        if (!$orderInfo) {
            $this->error("订单不存在");
        }

        $state = ['ToBePaid', 'Paid', 'Received', 'SetOut', 'Reach'];

        if (!in_array($orderInfo->order_state, $state)) {
            $this->error("订单状态不允许取消");
        }

        // 优惠券更改为未使用状态
        if ($orderInfo->user_coupon_id) {
            Db::table("ba_user_coupon")
                ->where([
                    'user_coupon_id' => $orderInfo->user_coupon_id
                ])
                ->update([
                    'is_apply' => 1,
                ]);
        }


        #加事务
        Db::startTrans();
        try {

            if ($orderInfo->order_state != 'ToBePaid') {
                //                if ($orderInfo->order_state == 'SetOut' || $orderInfo->order_state == 'Reach') {
                #查看技师出行是否免费
//                    $is_travel = Technician::where('technician_id', $orderInfo->technician_id)->value('is_travel');
//                    $fare_price = FareOrder::where('order_id', $orderInfo->id)->value('fare_price');
//                    if ($is_travel == 0 && $fare_price == 0) {
//                        throw new Exception('等待技师上传车费凭证');
//                    }
//                }

                #退款
                $refund = new Refund($orderInfo->order_sn, $orderInfo->payment_order_sn);
                $pay_way = $orderInfo->pay_way;
                $refund->$pay_way();

            }
            $orderInfo->cancel_remarks = $cancel_remarks;
            $orderInfo->order_state = 'Canceled';
            $orderInfo->save();


            #取消技师预约
            Db::name('order_reservation')->where('technician_id', $orderInfo->technician_id)->where('reservation_time', date("Y-m-d H:i", strtotime($orderInfo->service_start_time)))->delete();
            #记录订单状态
            setOrderStateLog($orderInfo->id, 'Canceled');
            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            Log::error('订单取消失败：user_id :' . $this->auth->id . ' order_id ' . $order_id . 'errMsg' . $e->getMessage());
            $this->error($e->getMessage());
        }

        $this->success("订单取消成功");
    }


    /**
     * 完成订单
     * @param int $order_id 订单ID
     * @return void
     */
    public function completeOrder(): void
    {
        $order_id = (int) $this->request->param('order_id');
        if (empty($order_id)) {
            $this->error("order_id 为必填项");
        }

        $orderInfo = $this->model->where('id', $order_id)->where('user_id', $this->auth->id)->find();

        if (!$orderInfo) {
            $this->error("订单不存在");
        }

        if ($orderInfo->order_state != 'Start' && $orderInfo->order_state != 'tchEnd') {
            $this->error("订单状态不允许完成");
        }

        $ret = (new OrderFunc)->completeService($orderInfo);
        if (!$ret) {
            $this->error("订单修改状态失败");
        }
        $this->success("订单已完成");
    }


    /**
     * 定时任务取消订单
     * @return void
     */
    public function TaskCancelOrder(): void
    {
        $orderList = $this->model->where('order_state', 'ToBePaid')->where('create_time', '<', date("Y-m-d H:i:s", time() - get_sys_config('remaining_time') * 60))->select();
        foreach ($orderList as $order) {
            $order->order_state = 'Canceled';
            $order->save();
            #记录订单状态
            setOrderStateLog($order->id, 'Canceled');
        }
    }


    /**
     * 定时任务完成订单
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function TaskCompleteOrder(): void
    {
        #查询订单状态为技师服务结束，但是时间已经过期的订单
        $orderInfo = \app\api\model\Order::where('order_state', 'tchEnd')->where('tchend_time', '<', date("Y-m-d H:i:s", time()))->field('id,order_state,evaluate_state,technician_id,type,service_reality_price,service_id,order_sn,service_start_time,user_id')->select();

        foreach ($orderInfo as $item) {
            $ret = (new OrderFunc)->completeService($item);
            if (!$ret) {
                Log::error('订单修改状态失败');
            }
        }
        Log::info('定时任务完成订单');
    }


    /**
     * 去支付
     * @return void
     */
    public function toPay(): void
    {
        $order_sn = $this->request->post('order_sn');

        $orderInfo = $this->model->where('order_sn', $order_sn)->where('user_id', $this->auth->id)->find();
        if (!$orderInfo) {
            $this->error('订单不存在');
        }

        if ($orderInfo->order_state != 'ToBePaid') {
            $this->error('订单状态不允许支付');
        }

        $serviceInfo = \app\admin\model\service\Service::where('service_id', $orderInfo->service_id)->find();

        #微信支付 JSApi支付
        $order = [
            'out_trade_no' => $orderInfo->order_sn,
            'description' => $serviceInfo->service_name,
            'amount' => [
                'total' => $orderInfo->service_total_price * 100, //分
            ],
            'payer' => [
                'openid' => $this->openid(),
            ],
            'attach' => 'orderPayCallback'   #扩展信息
        ];
        $result = Pay::wechat(PayLib::getConfig())->mp($order);
        Log::info('去支付-返回下单信息' . json_encode($result));
        $this->success("创建支付成功", ['order_sn' => $orderInfo->order_sn, 'pay_url' => $result]);
    }


    /**
     * 获取订单时间线
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getOrderLine(): void
    {
        $line = [
            [
                "id" => 0,
                "title" => "接单",
                "desc" => '技师已接单',
                "time" => '',
                "istrue" => false,
                "order_state" => "Received"
            ],
            [
                "id" => 1,
                "title" => "出发",
                "desc" => '技师已出发',
                "time" => '',
                "istrue" => false,
                "order_state" => "SetOut"
            ],
            [
                "id" => 2,
                "title" => "到达",
                "desc" => '技师已到达',
                "time" => '',
                "istrue" => false,
                "order_state" => "Reach"
            ],
            [
                "id" => 3,
                "title" => "服务",
                "desc" => '开始服务',
                "time" => '',
                "istrue" => false,
                "order_state" => "Start"
            ],
            [
                "id" => 4,
                "title" => "订单结束",
                "desc" => '完成服务',
                "time" => '',
                "istrue" => false,
                "order_state" => "Completed"
            ],
        ];
        $order_id = $this->request->param('order_id');
        $type = \app\api\model\Order::where('id', $order_id)->value('type');
        $list = Db::name('order_state_timeline')->where('order_id', $order_id)->order('create_time', 'asc')->select();

        foreach ($line as $key => $value) {
            foreach ($list as $v) {
                if ($v['order_state'] == $value['order_state']) {
                    $line[$key]['time'] = $v['create_time'];
                    $line[$key]['istrue'] = true;
                }
            }
            if ($type == 2 && $key < 3) {
                unset($line[$key]);
            }
        }
        $line = array_values($line);

        $this->success('', $line);
    }


    public function refund()
    {
        #微信支付 JSApi支付
        $order = [
            'out_trade_no' => '202405241730265796921122',
            'transaction_id' => '4200002171202405240350102188',
            'out_refund_no' => '42000a0a2q15aa92a0s2a40a5a205105503496aa',
            'amount' => [
                'refund' => 19800, //分
                'total' => 19800,//分
                'currency' => 'CNY',
            ],
            '_action' => 'jsapi', // jsapi 退款，默认

        ];
        $result = Pay::wechat(PayLib::getConfig())->refund($order);
        $this->success('', $result);
    }
}